<?php

namespace Shahu\Common\common\jwtAuth;

use ReflectionClass;
use ReflectionException;
use Shahu\Common\controller\AdminBaseController;
use Shahu\Common\exception\ValidateException;
use Webman\Http\Request;

class Validate
{
    /**
     * 检查授权
     * @param Request $request
     * @return void
     * @throws ReflectionException
     * @throws ValidateException
     */
    public static function check(Request $request) : void
    {
        //当前参数
        $params = $request->all();

        if (class_exists('app\constant\ValidateConstant')) {
            //获取所有验证配置
            $current_validate_arr = \app\constant\ValidateConstant::RULE_MAP[$request->controller] ?? [];

            //获取当前调用对应的验证器
            if (array_key_exists($request->action, $current_validate_arr)) {
                //获取规则
                list($total_rules, $messages) = static::getRulesAndMessage($current_validate_arr[$request->action]);
                //检验
                static::checkRule($params, $total_rules, $messages);
            }
        }

        AdminBaseController::$params = $params;
    }


    /**
     * 实例化
     * @param $validate_class
     * @return array
     * @throws ReflectionException
     */
    private static function getRulesAndMessage($validate_class) : array
    {
        //实例化方法
        $class = new ReflectionClass($validate_class);
        $instance = $class->newInstance();
        //获取规则
        $role = $class->getMethod('rules')->invoke($instance);
        $message = $class->getMethod('messages')->invoke($instance);

        //返回
        return [$role, $message];
    }



    private static function checkRule(array $params, array $total_rules, $messages): void
    {
        //遍历
        foreach ($total_rules as $key => $field_rules) {
            $tmp_field_data = $params[$key] ?? NULL;
            foreach ($field_rules as $rule) {
                //分离规则和条件
                $split_arr = explode(':', $rule);
                //规则
                $rule = $split_arr[0] ?? $rule;
                //额外条件
                $condition = $split_arr[1] ?? null;
                //规则列表
                $res = static::ruleMap($rule, $condition, $tmp_field_data);
                if (!$res) {
                    $message_key = $key.'.'.$rule;
                    //读取错误信息
                    $error_message = $messages[$message_key] ?? '';
                    if (empty($error_message)) {
                        throw new ValidateException('传入参数验证失败');
                    } else {
                        throw new ValidateException($error_message);
                    }
                }
            }
        }
    }



    private static function ruleRequired($field_data) : bool
    {
        //非null
        if (!is_null($field_data)) {
            //数组和对象判断空
            if (is_object($field_data) || is_array($field_data)) {
                if (!empty($field_data)) {
                    return true;
                }
            } else {
                //其他转字符串判断长度
                if (strlen(strval($field_data)) > 0) {
                    return true;
                }
            }
        }
        return false;
    }

    /************
     * 数据格式校验
     * **********
     */

    private static function ruleInteger($field_data): bool
    {
        return is_int($field_data);
    }

    private static function ruleNumeric($field_data): bool
    {
        return is_numeric($field_data);
    }

    private static function ruleString($field_data) : bool
    {
        return is_string($field_data);
    }

    private static function ruleArray($field_data) : bool
    {
        return is_array($field_data);
    }

    private static function ruleBoolean($field_data) : bool
    {
        return is_bool($field_data);
    }

    private static function ruleDate($field_data): bool
    {
        if(strtotime($field_data) === false)
        {
            return false;
        }
        return true;
    }

    private static function ruleEmail($field_data): bool
    {
        if (preg_match('/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/', $field_data)) {
            return true;
        }
        return false;
    }


    private static function ruleUrl($field_data): bool
    {
        if (preg_match("@^(https?|ftp)://[^\s/$.?#].\S*$@iS", $field_data)) {
            return true;
        }
        return false;
    }


    private static function ruleJson($field_data): bool
    {
        if (preg_match('/[^,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]/', preg_replace('/"(\\.|[^"\\\\])*"/', '', $field_data))) {
            return true;
        }
        return false;
    }


    private static function ruleUuid($field_data): bool
    {
        if (preg_match("/[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/", $field_data)) {
            return true;
        }
        return false;
    }


    private static function ruleDistinct($field_data): bool
    {
        if (is_array($field_data)) {
            $total_count = array_count_values($field_data);
            foreach ($total_count as $count) {
                if ($count > 1) {
                    return false;
                }
            }
            return true;
        }
        return true;
    }


    private function ruleGt($field_data, $condition): bool
    {
        if ($field_data > $condition) {
            return true;
        }
        return false;
    }


    private function ruleGte($field_data, $condition): bool
    {
        if ($field_data >= $condition) {
            return true;
        }
        return false;
    }


    private function ruleLt($field_data, $condition): bool
    {
        if ($field_data < $condition) {
            return true;
        }
        return false;
    }


    private function ruleLte($field_data, $condition): bool
    {
        if ($field_data <= $condition) {
            return true;
        }
        return false;
    }

    private function ruleStartWith($field_data, $condition): bool
    {
        if (str_starts_with($field_data, $condition)) {
            return true;
        }
        return false;
    }


    private function ruleNotStartWith($field_data, $condition): bool
    {
        if (!str_starts_with($field_data, $condition)) {
            return true;
        }
        return false;
    }


    private function ruleEndWith($field_data, $condition): bool
    {
        if (str_ends_with($field_data, $condition)) {
            return true;
        }
        return false;
    }

    private function ruleNotEndWith($field_data, $condition): bool
    {
        if (!str_ends_with($field_data, $condition)) {
            return true;
        }
        return false;
    }


    private static function ruleIn($field_data, $condition): bool
    {
        if (is_array($condition)) {
            if (in_array($field_data, $condition)) {
                return true;
            }
            return false;
        }
        return true;
    }

    private static function ruleNotIn($field_data, $condition): bool
    {
        if (!is_array($condition)) {
            if (in_array($field_data, $condition)) {
                return true;
            }
            return false;
        }
        return true;
    }


    private static function ruleBetween($field_data, $condition): bool
    {
        return true;
    }


    private static function ruleSize($field_data, $condition): bool
    {
        return true;
    }




    private static function ruleRegex($field_data, $condition): bool
    {
        if (preg_match($condition, $field_data)) {
            return true;
        }
        return false;
    }


    private static function ruleNotRegex($field_data, $condition): bool
    {
        if (preg_match($condition, $field_data)) {
            return false;
        }
        return true;
    }


    /**
     * 规则映射
     * @param $rule
     * @param $condition
     * @param $field_data
     * @return bool
     */
    private static function ruleMap($rule, $condition, $field_data) : bool
    {
        //调用规则
        $method = 'rule'.ucfirst($rule);
        return static::$method($field_data, $condition);
    }
}
